#!/usr/bin/env python
# _*_ coding: UTF-8 _*_

import sys
from SSHBatch import Utilities

class Configure:
    CLUSTER_HOSTS_MAXSIZE = 254
    
    def __init__(self, fpath = None):
        self.configs = {}
        self.initConfigs()
        if fpath: self.load(fpath)

    def __getitem__(self, name):
        if name in ["Global", "Clusters", "Hosts", "Ssh"]:
            return self.configs[name]

    def initConfigs(self):
        self.configs["Global"] = {}
        self.configs["Ssh"] = {}
        self.configs["Clusters"] = {}
        self.configs["Hosts"] = {}

        self.configs["Global"]["sshbatchid"] = "ssb"
        self.configs["Global"]["history"] = "~/.sshbatch.his"
        self.configs["Global"]["editor"] = "/usr/bin/vi"
        
        self.configs["Ssh"]["path"] = "ssh"
        self.configs["Ssh"]["port"] = "22"
        self.configs["Ssh"]["user"] = "root"
        self.configs["Ssh"]["password"] = ""
    
    def checkCompletion(self, configs):
        for clusterid in configs["Clusters"].keys():
            for hostid in configs["Clusters"][clusterid]:
                if hostid not in configs["Hosts"].keys():
                    self.setHosts(hostid, hostid, configs["Hosts"])

    def setGlobal(self, key, value, configs):
        keys = ["sshbatchid", "history", "editor"]
        if not key in keys:
            raise SyntaxError("Invalid configured global item")
        configs[key] = value

    def setSsh(self, key, value, configs):
        keys = ["path", "port", "user", "password"]
        if not key in keys:
            raise SyntaxError("Invalid configured ssh item")
        configs[key] = value

    def setClusters(self, key, value, configs):
        hosts = map(lambda item:item.strip(), Utilities.string_split(value, ",;"))
        values = []
        for host in hosts:
            hlist = map(lambda item:item.strip(), host.strip().split("-"))
            if len(hlist) == 1 and hlist[0]:
                values.append(hlist[0])
            elif len(hlist) == 2 and hlist[0] and hlist[1]:
                start, sremain = Utilities.stringr2int(hlist[0], True)
                end, eremain = Utilities.stringr2int(hlist[1], True)
                if start == None or end == None or sremain != eremain or start > end:
                    raise SyntaxError("Cluster hosts out of range")
                numlen = len(hlist[0]) - len(sremain)
                while start <= end:
                    strnum = str(start)
                    if len(strnum) < numlen:
                        strnum = "0"*(numlen - len(strnum)) + strnum
                    values.append("%s%s" % (sremain, strnum))
                    start = start + 1
            else:
                raise SyntaxError("Invalid cluster configured")
        if len(values) > Configure.CLUSTER_HOSTS_MAXSIZE:
            raise ValueError("Too many cluster hosts")
        configs[key] = values

    def setHosts(self, key, value, configs):
        host = {}
        host["user"] = self.configs["Ssh"]["user"]
        host["password"] = self.configs["Ssh"]["password"]
        host["port"] = self.configs["Ssh"]["port"]
        host["hostname"] = key
        
        uri_parts = Utilities.uri_parse(value)
        if uri_parts["user"]: 
            host["user"] = uri_parts["user"]
        if uri_parts["password"]: 
            host["password"] = uri_parts["password"]
        if uri_parts["port"]: 
            host["port"] = uri_parts["port"]
        if uri_parts["hostname"]: 
            host["hostname"] = uri_parts["hostname"]
        configs[key] = host

    def clear(self):
        self.configs = {}

    def load(self, fpath):
        grouplist = ["Global", "Ssh", "Clusters", "Hosts"]
        groups = {"Global":[], "Ssh":[], "Clusters":[], "Hosts":[]}
        group = "Global"
        fh = open(fpath, "r")
        lineno = 0
        for line in fh.readlines():
            lineno = lineno + 1
            line = line.strip()
            if len(line) == 0 or line[0] == '#':
                continue    
            if line[0] == '[' and line[-1] == ']':
                tgroup = line[1:-1].strip()
                if len(tgroup) <= 0:
                    raise SyntaxError("Line %d:Empty group name" % lineno)
                group = tgroup.lower().capitalize()
                
                if not group in groups:
                    raise SyntaxError("Line %d:Unknown group name" % lineno)
                continue
            pair = line.split('=', 1)
            key = pair[0].strip()
            if len(key) == 0:
                continue
            value = ""
            if len(pair)>1:
                value = pair[1].strip()
            groups[group].append(tuple([lineno, key, value]))
        fh.close()
        
        for group in grouplist:
            for lineno, key, value in groups[group]:
                try:
                    Configure.__dict__["set" + group](self, key, value, self.configs[group])
                except SyntaxError, se:
                    raise SyntaxError("Line %d:%s" % (lineno, str(se)))
                except ValueError, ve:
                    raise ValueError("Line %d:%s" % (lineno, str(ve)))
        self.checkCompletion(self.configs)

    def getConfigs(self):
        return self.configs
    
    def dumpConfigs(self, fhandle = sys.stdout):
        for group in ["Global", "Ssh", "Clusters", "Hosts"]:
            fhandle.write("[%s]\n" % group)
            for key in self.configs[group].keys():
                fhandle.write("%s = %s\n" % (key, self.configs[group][key]))
            fhandle.write("\n")

def main():
    import sys
    if len(sys.argv) != 2:
        print "Usage: Configure.py config-file"
        sys.exit(1)
    cfg = Configure(sys.argv[1])
    print cfg.getConfigs()

if __name__ == "__main__":
    main()
